import jpype

from io import BytesIO
from pathlib import Path

from PIL import Image
import jpype.imports
from jpype.types import JArray, JByte


class PyZXing:
    def __init__(self):
        self.image = None
        self.objs = []

    def decode(self, image):
        PyZXing.init_jvm()

        from java.io import ByteArrayInputStream
        from javax.imageio import ImageIO

        from com.google.zxing import BinaryBitmap
        from com.google.zxing import MultiFormatReader
        from com.google.zxing.client.j2se import BufferedImageLuminanceSource
        from com.google.zxing.client.result import ParsedResult
        from com.google.zxing.client.result import ResultParser
        from com.google.zxing.common import HybridBinarizer
        from com.google.zxing.multi import GenericMultipleBarcodeReader

        self.image = image.convert("RGBA")
        self.objs = []

        ios = BytesIO()
        self.image.save(ios, "png")
        contents = ios.getbuffer()

        JByteArray = JArray(JByte)
        bufferedImage = ImageIO.read(ByteArrayInputStream(JByteArray(contents)))
        luminanceSource = BufferedImageLuminanceSource(bufferedImage)
        binarizer = HybridBinarizer(luminanceSource)
        binaryBitmap = BinaryBitmap(binarizer)

        try:
            results = GenericMultipleBarcodeReader(MultiFormatReader()).decodeMultiple(
                binaryBitmap
            )
        except BaseException:
            results = []

        for result in results:
            parsedResult = ResultParser.parseResult(result)

            self.objs.append(self.parse_result(result, parsedResult))

        return self.objs

    def crop(self, obj):
        points = obj.get("points")

        if not points:
            return None

        if len(points) >= 4:
            x = None
            y = None
            x2 = None
            y2 = None

            for point in points:
                if x is None:
                    x = point[0]
                else:
                    x = min(point[0], x)

                if y is None:
                    y = point[1]
                else:
                    y = min(point[1], y)

                if x2 is None:
                    x2 = point[0]
                else:
                    x2 = max(point[0], x2)

                if y2 is None:
                    y2 = point[1]
                else:
                    y2 = max(point[1], y2)

            try:
                return self.image.crop((x, y, x2, y2))
            except BaseException:
                pass

        return None

    def parse_result(self, result, parsedResult):
        obj = {
            "format": str(result.getBarcodeFormat()),
            "type": str(parsedResult.getType()),
            "data": parsedResult.getDisplayResult(),
            "points": [],
            "background": None,
        }

        for point in result.getResultPoints():
            obj["points"].append((point.getX(), point.getY()))

        if obj.get("points"):
            obj["background"] = self.image.getpixel(obj.get("points")[0])

        return obj

    @classmethod
    def init_jvm(cls):
        if not jpype.isJVMStarted():
            BASE_DIR = Path(__file__).parent

            filename = BASE_DIR.joinpath("bin/zxing.jar").as_posix()
            jpype.startJVM(classpath=[filename])
